package fileDemo;

import password.MD5Utils;

import java.io.*;

/**
 * @author Ajie
 * @date 2023/8/8
 * @function
 *
 * // step3.2:在“续传”行为开始后，通过RandomAccessFile类来包装我们的文件，
 * // 然后通过seek将指针指定到之前发生中断的位置进行读写就搞定了。
 * //（实际的文件下载上传，我们当然需要将保存的中断值上传给服务器，这个方式通常为
 *
 *             RandomAccessFile readFile = new RandomAccessFile(source, "rw");
 *             RandomAccessFile writeFile = new RandomAccessFile(target, "rw");
 *             readFile.seek(position);
 *             writeFile.seek(position);
 *
 */
public class DownLoad_断点续传 {
    // step1:首先，我们定义了一个变量position，记录在发生中断的时候，已完成读写的位置。（这是为了方便，实际来说肯定应该讲这个值存到文件或者数据库等进行持久化）
    private static int position = -1;

    public static void main(String[] args) {
        // 源文件与目标文件
        File sourceFile = new File("./src/fileDemo/", "DownLoad_断点续传_sourceFile.txt");
        File targetFile = new File("./src/fileDemo/", "DownLoad_断点续传_targetFile.txt");
        // 输入输出流
        FileInputStream fis = null;
        FileOutputStream fos = null;
        // 数据缓冲区
        byte[] buf = new byte[1];

        try {
            fis = new FileInputStream(sourceFile);
            fos = new FileOutputStream(targetFile);
            // 数据读写
            while (fis.read(buf) != -1) {
                fos.write(buf);
                // step2:然后在文件读写的while循环中，我们去模拟一个中断行为的发生。这里是当targetFile的文件长度为3个字节则模拟抛出一个我们自定义的异常。
                // (我们可以想象为实际下载中，已经上传(下载)了”x”个字节的内容，这个时候网络中断了，那么我们就在网络中断抛出的异常中将”x”记录下来)。
                if (targetFile.length() == 3) {//TODO 自定义下载中断
                    position = 3;
                    throw new FileAccessException();
                }
            }
        } catch (FileAccessException e) {
            //step3:开启”续传“行为，即keepGoing方法.
            e.printStackTrace();
            System.out.println("DownLoad_断点续传:main:自定义中断。");
            keepGoing(sourceFile, targetFile, position);
        } catch (FileNotFoundException e) {
            System.out.println("指定文件不存在");
        } catch (IOException e) {
            // TODO: handle exception
        } finally {
            try {
                // 关闭输入输出流
                if (fis != null)
                    fis.close();

                if (fos != null)
                    fos.close();
            } catch (IOException e) {
                e.printStackTrace();
            }

        }

        System.out.println("DownLoad_断点续传:main:equals:"+(MD5Utils.md5File(targetFile.getAbsolutePath()).equals(MD5Utils.md5File(sourceFile.getAbsolutePath()))));
    }

    private static void keepGoing(File source, File target, int position) {
// step3.1:我们起头让线程休眠10秒钟，这正是为了让我们运行程序看到效果。
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        System.out.println("DownLoad_断点续传:keepGoing:开始从 断点 继续。");

// step3.2:在“续传”行为开始后，通过RandomAccessFile类来包装我们的文件，
// 然后通过seek将指针指定到之前发生中断的位置进行读写就搞定了。
//（实际的文件下载上传，我们当然需要将保存的中断值上传给服务器，这个方式通常为
        try {
            RandomAccessFile readFile = new RandomAccessFile(source, "rw");
            RandomAccessFile writeFile = new RandomAccessFile(target, "rw");
            readFile.seek(position);
            writeFile.seek(position);

            // 数据缓冲区
            byte[] buf = new byte[1];
            // 数据读写
            while (readFile.read(buf) != -1) {
                writeFile.write(buf);
            }
        } catch (FileNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
}

class FileAccessException extends Exception {

}

